//////////// SHARE CONSTANTS ////////////////////
var TYPE = new Object();

//Appication
TYPE.GET_TAB_ID = "GetTabId";
TYPE.GET_SITE_VALUE = "GetSiteValue";
TYPE.SEND_DATA_TAB_ID = "SendDataTabId";
TYPE.SEND_SITE_VALUE = "SendSiteValue";
TYPE.SEND_UNIT_PER_BET_VALUE = "SEND_UNIT_PER_BET_VALUE";
TYPE.START_MATCH = "StartMatch";
TYPE.STOP_MATCH = "StopMatch";
TYPE.LOG_INFO = "LogInfo";
TYPE.LOG_SUCCESS = "LogSucess";
TYPE.LOG_HIDDEN = "LogHidden";
TYPE.LOG_SITE_DATA = "LogSiteData";
TYPE.SET_UNIT_PER_BET = "SetUnitPerBet";
var SAI_SO = 0.02;

//Content script
TYPE.GET_DOM_FOR_CHECK = "GetDOMForCheck";
TYPE.GET_DOM_FOR_PROCESS = "GetDOMForProcess";
TYPE.ADD_REMARK_BETTING = "AddRemarkBettingData";
TYPE.REMOVE_REMARK_BETTING = "RemoveRemarkBettingData";

var SITE_ARRAY = new Array("mara", "padd", "plan", "pari", "beti","favbet");
////////////////////////////////////////////////

//////////// LOCAL CONSTANTS ////////////////////
var SET_DATA_TYPE = new Object();
SET_DATA_TYPE.TEAM1_VALUE = "Team1Value";
SET_DATA_TYPE.TEAM2_VALUE = "Team2Value";

var TIME_WAIT_UPDATE_ODDS = 200; //miliseconds
var TIME_CIRCEL = 1000; //miliseconds
var TIMES_BETTING_COUNT = 5;//=> the time is TIMES_BETTING_COUNT * TIME_CIRCEL (miliseconds)
var MIN_ODDS = 1.15;
var RATE_MIN = 1.05;
var BETTING_UNIT = 50;
var TIME_WAIT_RESTART = 20; //seconds

var APP_ID = "glhcjmchggganfmgebcmjlkfjbidiaoh";
var GlobalData = {};
var PreviousData = {};

////////////////////////////////////////////////

/////////////////// PUBLIC FUNCTIONS /////////////////////////////////////
chrome.runtime.onMessageExternal.addListener(
        function(request, sender, sendResponse) {
            switch (request.Type) {
                case TYPE.GET_TAB_ID:
                    GetTabId(request.Data);
                    break;
                case TYPE.GET_SITE_VALUE:
                    GetSiteValue(request.Data);
                    break;
                case TYPE.START_MATCH:
                    StartMatch(request.Data);
                    break;
                case TYPE.STOP_MATCH:
                    StopMatch(request.Data);
                    break;
                case TYPE.SET_UNIT_PER_BET:
                    SetUnitPerBet(request.Data);
                    break;
            }
        });

// Audio initation
var audioElement = document.createElement('audio');
audioElement.setAttribute("preload", "auto");
audioElement.autobuffer = true;

var source1 = document.createElement('source');
source1.type = 'audio/mpeg';
source1.src = chrome.runtime.getURL("alert.mp3");
audioElement.appendChild(source1);

///////////////////////////// END PUBLIC FUNCTIONS //////////////////////////

////////////////////////  GETTING FUNCTIONS ////////////////////////////

function SetUnitPerBet(data)
{
    BETTING_UNIT = data.Value;
    SendToApp(TYPE.SEND_UNIT_PER_BET_VALUE, {Value: BETTING_UNIT})
}

function GetTabId(data) {

    //Check url opened
    chrome.windows.getAll({populate: true}, function(windows) {

        var tabId = -1;
        for (var wi = 0; wi < windows.length; wi++) {

            var contentWindow = windows[wi];
            for (var ti = 0; ti < contentWindow.tabs.length; ti++) {
                var contentTab = contentWindow.tabs[ti];
                if (contentTab.url === data.SiteUrl) {
                    tabId = contentTab.id;
                    break;
                }
            }
            if (tabId !== -1)
                break;
        }

        SendToApp(TYPE.SEND_DATA_TAB_ID, {MatchId: data.MatchId, SiteKey: data.SiteKey, TabId: tabId});
    });
}

function GetSiteValue(data) {
    GetOdds(data, true);
    GetOdds(data, false);
}

function GetOdds(data, isCheckValueOne) {

    var filter = null;
    var key = null;
    if (isCheckValueOne) {
        filter = data.ValueOne.Value;
        key = data.ValueOne.Key;
    } else {
        filter = data.ValueTwo.Value;
        key = data.ValueTwo.Key;
    }

    var sendContentData = {
        MatchId: data.MatchId,
        PairId: data.PairId,
        Key: key,
        SiteType: data.SiteType,
        Filter: filter
    };

    var responseFunction = function(data) {
        var sendAppdata = {
            MatchId: data.MatchId,
            PairId: data.PairId,
            Key: data.Key,
            Value: data.Value
        };
        SendToApp(TYPE.SEND_SITE_VALUE, sendAppdata);
    };

    SendToContenScript(data.TabId, TYPE.GET_DOM_FOR_CHECK, sendContentData, responseFunction);
}

function SendToApp(type, sendData) {
    var data = {Type: type, Data: sendData};
    chrome.runtime.sendMessage(APP_ID, data, null);
}

function SendToContenScript(tabId, type, sendData, responseFunction) {
    var data = {Type: type, Data: sendData};
    chrome.tabs.sendMessage(tabId, data, responseFunction);
}

function ShowNotification(title, message) {
    var iconPath = chrome.runtime.getURL("icon_16.png");
    new Notification(title, {body:message, icon: iconPath});
}

////////////////////////  END GETTING FUNCTIONS ////////////////////////////

////////////////////////  MATCH PROCESSING ////////////////////////////

function StartMatch(data) {

    // Clear current process
    if (GlobalData[data.MatchId] && GlobalData[data.MatchId].IntervalId) {
        clearInterval(GlobalData[data.MatchId].IntervalId);
    }

    SetMatchData(data);
    GlobalData[data.MatchId].IntervalId = setInterval(BackgroundProcess, TIME_CIRCEL, data.MatchId);
}

function SetMatchData(data) {
    GlobalData[data.MatchId] = data;
    PreviousData[data.MatchId] = null;

    //Reset variables
    GlobalData[data.MatchId].BettingFlag = false;
    GlobalData[data.MatchId].BettingWaitTimes = 0;
    GlobalData[data.MatchId].BettingFlagTemp = false;
    GlobalData[data.MatchId].BettingTempCount = 0;

    //Update data
    SetPairsData(data.MatchId);
}

function SetPairsData(matchId) {
    var data = GlobalData[matchId];
    for (var pairIndex = 0; pairIndex < data.Pairs.length; pairIndex++) {
        var pair = data.Pairs[pairIndex];
        //Set Site A values
        SetSiteData(SET_DATA_TYPE.TEAM1_VALUE, data.MatchId, data.ATabId, data.ASiteType, pair.Sites[0].Team1Key, pairIndex, 0);
        SetSiteData(SET_DATA_TYPE.TEAM2_VALUE, data.MatchId, data.ATabId, data.ASiteType, pair.Sites[0].Team2Key, pairIndex, 0);

        //Set Site B values
        SetSiteData(SET_DATA_TYPE.TEAM1_VALUE, data.MatchId, data.BTabId, data.BSiteType, pair.Sites[1].Team1Key, pairIndex, 1);
        SetSiteData(SET_DATA_TYPE.TEAM2_VALUE, data.MatchId, data.BTabId, data.BSiteType, pair.Sites[1].Team2Key, pairIndex, 1);
    }
}

function SetSiteData(type, matchId, tabId, siteType, key, pairIndex, siteIndex) {
    //reset value
    SetSiteInfoData(type, null, matchId, pairIndex, siteIndex, true);

    var data = {
        SiteType: siteType,
        Key: key,
        MatchId: matchId,
        PairIndex: pairIndex,
        SiteIndex: siteIndex
    };
    chrome.tabs.sendMessage(tabId, {Type: TYPE.GET_DOM_FOR_PROCESS, Data: data}, function(rspData) {
        SetSiteInfoData(type, rspData.Value, rspData.MatchId, rspData.PairIndex, rspData.SiteIndex);
    });
}

function SetSiteInfoData(type, value, matchId, pairIndex, siteIndex, isClear) {
    var siteName = siteIndex === 0 ? "Main" : "Assistant";
    var message = "";
    switch (type) {
        case SET_DATA_TYPE.TEAM1_VALUE:
            message = CM_Function.StringFormat("-{0}: Set value {1} = {2}", siteName, "Team 1", value);
            GlobalData[matchId].Pairs[pairIndex].Sites[siteIndex].Team1Value = value;
            break;
        case SET_DATA_TYPE.TEAM2_VALUE:
            GlobalData[matchId].Pairs[pairIndex].Sites[siteIndex].Team2Value = value;
            message = CM_Function.StringFormat("-{0}: Set value {1} = {2}", siteName, "Team 2", value);
            break;
    }
    
    if(isClear) return;
    
    var date = new Date();
    var time = CM_Function.StringFormat("[{0}:{1}.{2}]", date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
    var data = {
        MatchId: matchId,
        PairId: GlobalData[matchId].Pairs[pairIndex].PairId,
        Time: time,
        Message: message
    };
    SendToApp(TYPE.LOG_SITE_DATA, data);
}

function BackgroundProcess(matchId) {
    try {

        //Check betting processing
        if (GlobalData[matchId].BettingFlag) {
            GlobalData[matchId].BettingWaitTimes++;
            if (TIME_CIRCEL * GlobalData[matchId].BettingWaitTimes <= TIME_WAIT_RESTART * 1000)
                return;
            
            //Reset Betting Flag
            RemoveRemarkBetting(matchId);
            GlobalData[matchId].BettingFlag = false;
            GlobalData[matchId].BettingWaitTimes = 0;
        }
        
        //Update Site Odds Value
        SendLogToApp(TYPE.LOG_INFO, matchId, "Data refreshing....");
        SetPairsData(matchId);

        //Check can bet
        setTimeout(function() {

            //Check Value Changed
            if (!IsValueChanged(matchId)) {

                SendLogToApp(TYPE.LOG_INFO, matchId, "Value not change.");
                if (GlobalData[matchId].BettingFlagTemp) {

                    GlobalData[matchId].BettingTempCount++;
                    SendLogToApp(TYPE.LOG_INFO, matchId, "Increase betting temp count to " + GlobalData[matchId].BettingTempCount);
                    if (GlobalData[matchId].BettingTempCount === TIMES_BETTING_COUNT) {

                        SendLogToApp(TYPE.LOG_INFO, matchId, "This is a wonderfull moment (^-^).");
                        GenerateNotification(matchId, GlobalData[matchId].BettingData);
                        SendSuccessLogToApp(TYPE.LOG_SUCCESS, matchId, GlobalData[matchId].BettingData);
                        AddRemarkBetting(matchId, GlobalData[matchId].BettingData);

                        //Set betting flag
                        GlobalData[matchId].BettingFlag = true;
                        GlobalData[matchId].BettingWaitTimes = 0;
                        GlobalData[matchId].BettingFlagTemp = false;
                        GlobalData[matchId].BettingTempCount = 0;
                    }
                }
                return;
            }
            //Set betting flag
            GlobalData[matchId].BettingFlag = false;
            GlobalData[matchId].BettingWaitTimes = 0;
            GlobalData[matchId].BettingFlagTemp = false;
            GlobalData[matchId].BettingTempCount = 0;

            SendLogToApp(TYPE.LOG_INFO, matchId, "Check value can bet...");
            for (var pairIndex = 0; pairIndex < GlobalData[matchId].Pairs.length; pairIndex++) {

                var pairDt = GlobalData[matchId].Pairs[pairIndex];
                ProcessPair(matchId, pairIndex, pairDt.Sites[0], pairDt.Sites[1]);

                if (GlobalData[matchId].BettingFlagTemp)
                    break;
            }

            //Store the old value
            PreviousData[matchId] = CloneGlobalData(matchId);
        }, TIME_WAIT_UPDATE_ODDS);
    } catch (er) {
    }
}

function IsValueChanged(matchId) {
    if (!PreviousData[matchId])
        return true;

    for (var pairIndex = 0; pairIndex < GlobalData[matchId].Pairs.length; pairIndex++) {

        var pair = GlobalData[matchId].Pairs[pairIndex];
        var prevPair = PreviousData[matchId].Pairs[pairIndex];
        for (var siteIndex = 0; siteIndex < pair.Sites.length; siteIndex++) {

            var site = pair.Sites[siteIndex];
            var prevSite = prevPair.Sites[siteIndex];

            var currentT1Value = site.Team1Value;
            var currentT2Value = site.Team2Value;
            var prevT1Value = prevSite.Team1Value;
            var prevT2Value = prevSite.Team2Value;
            if (!currentT1Value || !currentT2Value || !prevT1Value || !prevT2Value)
                return false;

            currentT1Value = parseFloat(site.Team1Value);
            currentT2Value = parseFloat(site.Team2Value);
            prevT1Value = parseFloat(prevSite.Team1Value);
            prevT2Value = parseFloat(prevSite.Team2Value);
            if (currentT1Value > prevT1Value + SAI_SO || currentT1Value < prevT1Value - SAI_SO ||
                    currentT2Value > prevT2Value + SAI_SO || currentT2Value < prevT2Value - SAI_SO)
                return true;
        }
    }
    return false;
}

function ProcessPair(matchId, pairIndex, firstDt, secondDt) {

    //Check get all value     
    var firstTeam1 = firstDt.Team1Value;
    var firstTeam2 = firstDt.Team2Value;
    var secondTeam1 = secondDt.Team1Value;
    var secondTeam2 = secondDt.Team2Value;
    if (!$.isNumeric(firstTeam1) || !$.isNumeric(firstTeam2) ||
            !$.isNumeric(secondTeam1) || !$.isNumeric(secondTeam2)) {
        return;
    }

    //Convert to number
    firstTeam1 = parseFloat(firstDt.Team1Value);
    firstTeam2 = parseFloat(firstDt.Team2Value);
    secondTeam1 = parseFloat(secondDt.Team1Value);
    secondTeam2 = parseFloat(secondDt.Team2Value);

    //Set selected value to process     
    var AValue, BValue;
    var AKey, BKey;
    if (firstTeam1 > secondTeam1 || firstTeam2 < secondTeam2) {
        AValue = firstTeam1;
        BValue = secondTeam2;

        AKey = firstDt.Team1Key;
        BKey = secondDt.Team2Key;
    } else {
        AValue = firstTeam2;
        BValue = secondTeam1;

        AKey = firstDt.Team2Key;
        BKey = secondDt.Team1Key;
    }

    //Anylise data     
    var result = AnyliseEachPair(AValue, BValue);
    if (result.IsOK) {

        //Log successful records
        result.AName = SITE_ARRAY[parseInt(firstDt.SiteID)];
        result.AOdds = AValue;
        result.BName = SITE_ARRAY[parseInt(secondDt.SiteID)];
        result.BOdds = BValue;
        result.AKey = AKey;
        result.BKey = BKey;

        //Init temp betting
        SendLogToApp(TYPE.LOG_INFO, matchId, "Set temp flag is true");
        GlobalData[matchId].BettingFlagTemp = true;
        GlobalData[matchId].BettingTempCount = 0;
        GlobalData[matchId].BettingData = result;
    }
}

function AnyliseEachPair(AValue, BValue) {
    var result = {IsOK: false};
    var lessNumber = AValue > BValue ? BValue : AValue;
    var greaterNumber = AValue > BValue ? AValue : BValue;
    if ((AValue - 1) * (BValue - 1) < RATE_MIN || lessNumber < MIN_ODDS)
    {
        return result;
    }
    var isALess = AValue < BValue;
    var bettingList = new Array();
    for (var start = Math.ceil((1 / (greaterNumber - 1) * BETTING_UNIT)); start < (lessNumber - 1) * BETTING_UNIT; start++)
    {
        var ccRow = new Object();
        ccRow.BetGreatNumber = start;
        ccRow.ProfitLessNumber = BETTING_UNIT * (lessNumber - 1) - start;
        ccRow.ProfitGreatNumber = start * (greaterNumber - 1) - BETTING_UNIT;
        bettingList.push(ccRow);
    }
    result.IsOK = bettingList.length !== 0;
    if(!result.IsOK)
    {
        return result;
    }
    
    var betting;
    if (lessNumber >= 2 && greaterNumber >= 2)
    {
        var maxOfMin = bettingList[0].ProfitGreatNumber > bettingList[0].ProfitLessNumber ? bettingList[0].ProfitLessNumber : bettingList[0].ProfitGreatNumber;
        betting = bettingList[0];
        for (var i = 1; i < bettingList.length; i++) {
            var min = bettingList[i].ProfitGreatNumber > bettingList[i].ProfitLessNumber ? bettingList[i].ProfitLessNumber : bettingList[i].ProfitGreatNumber;
            if (maxOfMin < min) {
                maxOfMin = min;
                betting = bettingList[i];
            }
        }
    }
    else if (lessNumber <= 1.4)
    {
        betting = bettingList[0];
    }
    else if (lessNumber <= 1.6)
    {
        if (bettingList.length < 3)
        {
            betting = bettingList[0];
        }
        else
        {
            betting = bettingList[1];
        }
    }
    else if (bettingList.length < 3)
    {
        betting = bettingList[0];
    }
    else if (bettingList.length < 7)
    {
        betting = bettingList[1];
    }
    else
    {
        betting = bettingList[2];
    }

    //Return value
    if (isALess)
    {
        result.BetA = BETTING_UNIT;
        result.BetB = betting.BetGreatNumber;
        result.ProfitA = betting.ProfitLessNumber;
        result.ProfitB = betting.ProfitGreatNumber;
    } else {
        result.BetA = betting.BetGreatNumber;
        result.BetB = BETTING_UNIT;
        result.ProfitA = betting.ProfitGreatNumber;
        result.ProfitB = betting.ProfitLessNumber;
    }
    result.IsALess = isALess;
    result.Rate = (AValue - 1) * (BValue - 1);
    return result;
}

function GenerateNotification(matchId, result) {

    //play sound
    audioElement.load;
    audioElement.play();
    var message = "";
    if (result.IsALess) {
        message += CM_Function.StringFormat("{0}: (O:{1}) {2}.\n", SITE_ARRAY[parseInt(GlobalData[matchId].ASiteType)], result.AOdds, result.BetA);
        message += CM_Function.StringFormat("{0}: (O:{1}) {2}.\n", SITE_ARRAY[parseInt(GlobalData[matchId].BSiteType)], result.BOdds, result.BetB);
    } else {
        message += CM_Function.StringFormat("{0}: (O:{1}) {2}.\n", SITE_ARRAY[parseInt(GlobalData[matchId].BSiteType)], result.BOdds, result.BetB);
        message += CM_Function.StringFormat("{0}: (O:{1}) {2}.\n", SITE_ARRAY[parseInt(GlobalData[matchId].ASiteType)], result.AOdds, result.BetA);
    }

    message += CM_Function.StringFormat("Rate: {0}.\n", result.Rate.toFixed(2));
    ShowNotification("INFORMATION", message);
}

function SendLogToApp(type, matchId, message) {
    var date = new Date();
    var content = CM_Function.StringFormat("[{0}:{1}.{2}]", date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
    content += " " + message;

    var data = {
        MatchId: matchId,
        Message: content
    };
    SendToApp(type, data);
}

function SendSuccessLogToApp(type, matchId, result) {
    var date = new Date();
    //Send visible log
    var message = CM_Function.StringFormat("[{0}:{1}.{2}] Rate: {3}", date.getHours(), date.getMinutes(), date.getSeconds(), result.Rate.toFixed(2));
    var data = {
        MatchId: matchId,
        Message: message
    };
    SendToApp(type, data);

    //Send log for anylize
    var dateString = date.getDate() + "_" + (date.getMonth() + 1) + "_" + date.getFullYear();
    dateString += "_" + date.getHours() + "_" + date.getMinutes() + "_" + date.getSeconds() + "_" + date.getMilliseconds();
    var AName = SITE_ARRAY[parseInt(GlobalData[matchId].ASiteType)];
    var BName = SITE_ARRAY[parseInt(GlobalData[matchId].BSiteType)];
    message = CM_Function.StringFormat("{0} {1} {2} {3} {4} {5} {6} {7} {8} {9}", dateString, AName, result.AOdds,
            BName, result.BOdds, result.Rate.toFixed(2), result.BetA, result.BetB, result.ProfitA.toFixed(2), result.ProfitB.toFixed(2));

    data = {
        MatchId: matchId,
        Message: message
    };
    SendToApp(TYPE.LOG_HIDDEN, data);
}

function CloneGlobalData(matchId) {

    var pairs = new Array();
    for (var pairIndex = 0; pairIndex < GlobalData[matchId].Pairs.length; pairIndex++) {
        var pair = GlobalData[matchId].Pairs[pairIndex];
        var sites = new Array();
        for (var siteIndex = 0; siteIndex < pair.Sites.length; siteIndex++) {
            var site = pair.Sites[siteIndex];
            sites.push(new SiteInfo(site.Team1Key, site.Team1Value, site.Team2Key, site.Team2Value));
        }
        pairs.push(new PairInfo(pair.PairId, sites));
    }
    return new MatchInfo(GlobalData[matchId].MatchId, GlobalData[matchId].ATabId, GlobalData[matchId].ASiteType, GlobalData[matchId].BTabId, GlobalData[matchId].BSiteType, pairs);
}

function AddRemarkBetting(matchId, result) {

    //Add remark the first site     
    var data = {
        Type: TYPE.ADD_REMARK_BETTING,
        MatchId: matchId,
        SiteType: GlobalData[matchId].ASiteType,
        Key: result.AKey,
        Value: result.AOdds
    };
    chrome.tabs.sendMessage(GlobalData[matchId].ATabId, {Type: TYPE.ADD_REMARK_BETTING, Data: data}, null);

    //add remark the second site
    data = {
        Type: TYPE.ADD_REMARK_BETTING,
        MatchId: matchId,
        SiteType: GlobalData[matchId].BSiteType,
        Key: result.BKey,
        Value: result.BOdds
    };
    chrome.tabs.sendMessage(GlobalData[matchId].BTabId, {Type: TYPE.ADD_REMARK_BETTING, Data: data}, null);

    //Set the less value tab selected
    var selectedTabId = result.IsALess ? GlobalData[matchId].ATabId : GlobalData[matchId].BTabId;
    chrome.tabs.update(selectedTabId, {active: true, highlighted: true});
}

function RemoveRemarkBetting(matchId) {

    var data = {
        Type: TYPE.ADD_REMARK_BETTING,
        MatchId: matchId
    };
    chrome.tabs.sendMessage(GlobalData[matchId].ATabId, {Type: TYPE.REMOVE_REMARK_BETTING, Data: data}, null);
    chrome.tabs.sendMessage(GlobalData[matchId].BTabId, {Type: TYPE.REMOVE_REMARK_BETTING, Data: data}, null);
}

function StopMatch(matchId) {
    clearInterval(GlobalData[matchId].IntervalId);
    RemoveRemarkBetting(matchId);
    SendLogToApp(TYPE.LOG_INFO, matchId, "Process stopped.");
}

////////////////////////  END MATCH PROCESSING ////////////////////////////
